#include "character.h"
#include "game_status.h"
#include <bitset>
#include <iostream>
#include <raylib.h>

Character::Character()
{
    // 二级跳
    this->doubleJumpTexture = LoadTexture("resources/Main Characters/Ninja Frog/Double Jump (32x32).png");
    this->doubleJumpSpeed = 3;
    this->doubleJumpWidth = 32;
    this->doubleJumpHeight = 32;
    this->doubleJumpCount = 0;
    this->doubleJumpTextureNum = 6;
    this->doubleJumpCurrentFrame = 0;
    this->doubleJumpFrameCounter = 0;
    this->doubleJumpFrameSpeed = 16;
    // 掉落
    this->fallTexture = LoadTexture("resources/Main Characters/Ninja Frog/Fall (32x32).png");
    this->fallSpeed = 4;
    // 打
    this->hitTexture = LoadTexture("resources/Main Characters/Ninja Frog/Hit (32x32).png");
    // 空闲
    this->idleTexture = LoadTexture("resources/Main Characters/Ninja Frog/Idle (32x32).png");
    this->idleTextureNum = 11;
    this->idleCurrentFrame = 0;
    this->idleFrameCounter = 0;
    this->idleFrameSpeed = 16;
    // 跳
    this->jumpTexture = LoadTexture("resources/Main Characters/Ninja Frog/Jump (32x32).png");
    this->jumpSpeed = 2;
    this->jumpMaxHeight = 8 * 8;
    this->doubleJumpMaxHeight = 8 * 8 * 2;
    // 跑
    this->runTexture = LoadTexture("resources/Main Characters/Ninja Frog/Run (32x32).png");
    this->runSpeed = 3;
    this->runTextureWidth = 32;
    this->runTextureHeight = 32;
    this->runTextureNum = 12;
    this->runCurrentFrame = 0;
    this->runFrameCounter = 0;
    this->runFrameSpeed = 16;
    // 墙壁跳
    this->wallJumpTexture = LoadTexture("resources/Main Characters/Ninja Frog/Wall Jump (32x32).png");

    // 基本属性
    this->status = 0 | CharacterStatusEnum::IDEL;
    this->jumpOldY = 0;
    this->x = float(GetScreenWidth()) / 2;
    this->y = float(GetScreenHeight()) - this->idleTexture.height - 8;
    this->width = 32;
    this->height = 32;
}

Character::~Character()
{
    UnloadTexture(this->doubleJumpTexture);
    UnloadTexture(this->fallTexture);
    UnloadTexture(this->hitTexture);
    UnloadTexture(this->idleTexture);
    UnloadTexture(this->jumpTexture);
    UnloadTexture(this->runTexture);
    UnloadTexture(this->wallJumpTexture);
}

void Character::Draw()
{
    float lastFrameTime = GetFrameTime() * 100;
    // 空闲
    if ((this->status & CharacterStatusEnum::IDEL) == CharacterStatusEnum::IDEL)
    {
        float idleTextureWidth = float(this->idleTexture.width) / this->idleTextureNum;

        this->idleFrameCounter += lastFrameTime * this->idleFrameSpeed;
        this->idleCurrentFrame = this->idleFrameCounter / idleTextureWidth;

        if (this->idleCurrentFrame > this->idleTextureNum)
        {
            this->idleCurrentFrame = 0;
        }
        if (this->idleFrameCounter > float(this->idleTexture.width))
        {
            this->idleFrameCounter = 0;
        }
        DrawTextureRec(this->idleTexture, Rectangle{this->idleCurrentFrame * idleTextureWidth, 0, 32, 32},
                       Vector2{this->x, this->y}, WHITE);
        idleFrameCounter++;
    }
    // 右跑
    if ((this->status & CharacterStatusEnum::RUN_RIGHT) == CharacterStatusEnum::RUN_RIGHT)
    {
        this->x += this->runSpeed;
        float runTextureWidth = float(this->runTexture.width) / this->runTextureNum;

        this->runFrameCounter += lastFrameTime * this->runFrameSpeed;
        this->runCurrentFrame = this->runFrameCounter / runTextureWidth;

        if (this->runCurrentFrame > this->runTextureNum)
        {
            this->runCurrentFrame = 0;
        }
        if (this->runFrameCounter > float(this->runTexture.width))
        {
            this->runFrameCounter = 0;
        }
        DrawTextureRec(
            this->runTexture,
            Rectangle{this->runCurrentFrame * runTextureWidth, 0, this->runTextureWidth, this->runTextureHeight},
            Vector2{this->x, this->y}, WHITE);
        runFrameCounter++;
        this->status = this->status ^ CharacterStatusEnum::RUN_RIGHT | CharacterStatusEnum::IDEL;
    }
    // 左跑
    if ((this->status & CharacterStatusEnum::RUN_LEFT) == CharacterStatusEnum::RUN_LEFT)
    {
        this->x -= this->runSpeed;
        float runTextureWidth = float(this->runTexture.width) / this->runTextureNum;

        this->runFrameCounter += lastFrameTime * this->runFrameSpeed;
        this->runCurrentFrame = this->runFrameCounter / runTextureWidth;

        if (this->runCurrentFrame > this->runTextureNum)
        {
            this->runCurrentFrame = 0;
        }
        if (this->runFrameCounter > float(this->runTexture.width))
        {
            this->runFrameCounter = 0;
        }
        DrawTextureRec(
            this->runTexture,
            Rectangle{this->runCurrentFrame * runTextureWidth, 0, this->runTextureWidth, this->runTextureHeight},
            Vector2{this->x, this->y}, WHITE);
        runFrameCounter++;
        this->status = this->status ^ CharacterStatusEnum::RUN_LEFT | CharacterStatusEnum::IDEL;
    }
    // 一级跳
    if (this->status & CharacterStatusEnum::JUMP)
    {
        float currentHeight = lastFrameTime * this->jumpSpeed;
        this->y -= currentHeight;
        if (this->y <= this->jumpOldY - this->jumpMaxHeight)
        {
            this->y = this->jumpOldY - this->jumpMaxHeight;
            this->status = this->status ^ CharacterStatusEnum::JUMP | CharacterStatusEnum::FALL;
        }
        DrawTexture(this->jumpTexture, this->x, this->y, WHITE);
    }
    // 二级跳
    if (this->status & CharacterStatusEnum::DOUBLE_JUMP)
    {
        float currentHeight = lastFrameTime * this->doubleJumpSpeed;
        this->y -= currentHeight;
        if (this->y <= this->jumpOldY - this->doubleJumpMaxHeight)
        {
            this->y = this->jumpOldY - this->doubleJumpMaxHeight;
            this->status = this->status ^ CharacterStatusEnum::DOUBLE_JUMP | CharacterStatusEnum::FALL;
        }

        float doubleJumpTextureWidth = float(this->doubleJumpTexture.width) / this->doubleJumpTextureNum;
        this->doubleJumpFrameCounter += lastFrameTime * this->doubleJumpFrameSpeed;
        this->doubleJumpCurrentFrame = this->doubleJumpFrameCounter / doubleJumpTextureWidth;

        if (this->doubleJumpCurrentFrame > this->doubleJumpTextureNum)
        {
            this->doubleJumpCurrentFrame = 0;
        }
        if (this->doubleJumpFrameCounter > float(this->doubleJumpTexture.width))
        {
            this->doubleJumpFrameCounter = 0;
        }
        DrawTextureRec(this->doubleJumpTexture,
                       Rectangle{this->doubleJumpCurrentFrame * doubleJumpTextureWidth, 0, this->doubleJumpWidth,
                                 this->doubleJumpHeight},
                       Vector2{this->x, this->y}, WHITE);
    }
    //  掉落
    if (this->status & CharacterStatusEnum::FALL)
    {
        float currentHeight = lastFrameTime * this->fallSpeed;
        this->y += currentHeight;
        if (this->y >= this->jumpOldY)
        {
            this->y = this->jumpOldY;
            this->status = this->status ^ CharacterStatusEnum::FALL | CharacterStatusEnum::IDEL;
            this->doubleJumpCount = 0;
        }
        DrawTexture(this->fallTexture, this->x, this->y, WHITE);
    }
}
void Character::checkPosition()
{
    if (this->x < 0)
    {
        this->x = 0;
    }
    if (this->x > GetScreenWidth() - this->width)
    {
        this->x = GetScreenWidth() - this->width;
    }
    if (this->y < 0)
    {
        this->y = 0;
    }
    if (this->y > GetScreenHeight() - this->height)
    {
        this->y = GetScreenHeight() - this->height;
    }
}
void Character::EventHandler(GameStatus *gameStatus)
{
    std::cout << "this->status: " << std::bitset<8>(this->status) << std::endl;
    bool isIdel = this->status & CharacterStatusEnum::IDEL;
    bool isJump = this->status & CharacterStatusEnum::JUMP;
    bool isDoubleJump = this->status & CharacterStatusEnum::DOUBLE_JUMP;
    bool isFall = this->status & CharacterStatusEnum::FALL;
    float lastFrameTime = GetFrameTime() * 100;
    // if (!isJump)
    // {
    //     this->status = CharacterStatusEnum::IDEL;
    // }
    if (IsKeyDown(KEY_RIGHT))
    {
        this->status = this->status ^ CharacterStatusEnum::IDEL | CharacterStatusEnum::RUN_RIGHT;
    }
    if (IsKeyDown(KEY_LEFT))
    {
        this->status = this->status ^ CharacterStatusEnum::IDEL | CharacterStatusEnum::RUN_LEFT;
    }
    if (!isJump && !isDoubleJump && !isFall && IsKeyPressed(KEY_UP))
    {
        this->status = this->status ^ CharacterStatusEnum::IDEL | CharacterStatusEnum::JUMP;
        this->jumpOldY = this->y;
    }
    if ((isJump || isFall) && this->doubleJumpCount <= 1 && IsKeyPressed(KEY_UP))
    {
        if (isJump)
        {
            this->status = this->status ^ CharacterStatusEnum::JUMP | CharacterStatusEnum::DOUBLE_JUMP;
        }
        if (isFall)
        {
            this->status = this->status ^ CharacterStatusEnum::FALL | CharacterStatusEnum::DOUBLE_JUMP;
        }
        this->doubleJumpCount++;
    }

    checkPosition();
}

Vector2 Character::GetLTP()
{
    return Vector2{this->x, this->y};
}

Vector2 Character::GetLBP()
{
    return Vector2{this->x, this->y + this->height};
}

Vector2 Character::GetRTP()
{
    return Vector2{this->x + this->width, this->y};
}

Vector2 Character::GetRBP()
{
    return Vector2{this->x + this->width, this->y + this->height};
}

Vector2 Character::GetBMP()
{
    return Vector2{this->x + this->width / 2, this->y + this->height};
}
